
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.reflect.Method;
import java.util.ArrayList;

import javax.swing.JOptionPane;

/**
 *
 * This abstract class is to implement the controller functionality of MVC.
 * For more detailed description, please check 
 * http://www.oracle.com/technetwork/articles/javase/mvc-136693.html
 *
 */
public abstract class AbstractController implements PropertyChangeListener {
	private ArrayList<AbstractView> registeredViews;
    private ArrayList<AbstractModel> registeredModels;

    public AbstractController() {
        registeredViews = new ArrayList<AbstractView>();
        registeredModels = new ArrayList<AbstractModel>();
    }

    public void addModel(AbstractModel model) {
        registeredModels.add(model);
        model.addPropertyChangeListener(this);
    }

    public void removeModel(AbstractModel model) {
        registeredModels.remove(model);
        model.removePropertyChangeListener(this);
    }

    public void addView(AbstractView view) {
        registeredViews.add(view);
    }

    public void removeView(AbstractView view) {
        registeredViews.remove(view);
    }

    /*
     * Triggered when a bound property is changed in model
     * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
     */
    public void propertyChange(PropertyChangeEvent evt) {
    	System.out.println(this.getClass().toString() + ".propertyChange() called-- " + 
				evt.getPropertyName() + ": " + evt.getOldValue().toString() + 
				" -> " + evt.getNewValue().toString());
        for (AbstractView view: registeredViews) {
            view.modelPropertyChange(evt);
        }
    }
    
    protected void setModelProperty(String propertyName, Object newValue) {
    	System.out.println(this.getClass().toString() + ".setModelProperty() called " + "-- set" + propertyName + "(" + newValue.getClass().toString() + ")");
        for (AbstractModel model: registeredModels) {
            try {
                Method method = model.getClass().
                    getMethod("set" + propertyName, new Class[] { newValue.getClass() });
                method.invoke(model, newValue);
            } catch (Exception ex) {
                // Handle exception. Ignored though.
            }
        }
    }

}
